import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Project, ProjectStatus } from "./project.entity";
import { FindOptionsWhere, Repository } from "typeorm";
import { System } from "src/system/system.entity";
import { Http } from "src/util/http";
import { Cron } from "@nestjs/schedule";
import { CacheService } from "src/cache/cache.service";
import { WorkStatus } from "src/work/work.entity";
import { UserSys } from "src/user/userSys.entity";
import { RoleEnum } from "src/role/role.enum";
import { WorkService } from "src/work/work.service";



@Injectable()
export class ProjectService {
    constructor(
        @InjectRepository(Project)
        public readonly project: Repository<Project>,
        private readonly cacheService: CacheService,
        private readonly workService: WorkService
    ) {
        this.autoLoadProjectRank();
    }

    async createWork(count: number, comment: string, projectid: number, createAt, user: UserSys) {
        const entity = this.workService.work.create({
            system: user.system,
            user,
            count,
            comment,
            createAt,
            dept: user.dept
        })
        const project = await this.project.findOne({
            where: {
                id: projectid,
                system: {
                    id: user.system.id
                }
            }
        })
        if (!project) throw Http.forbidden("找不到项目")
        entity.project = project
        return await this.workService.work.save(entity)
    }

    public getProjectWhere(user: UserSys) {
        const where: FindOptionsWhere<Project> = {};
        if (user.role === RoleEnum.director) {
            where.system = { id: user.system.id }
        } else if (user.role !== RoleEnum.boos) {
            where.user = { id: user.id }
        }
        return where;
    }

    async create(data: Project, system: System) {
        if (!system) throw Http.forbidden("拒绝访问")
        const entity = this.project.create(data)
        entity.system = system;
        const result = await this.project.save(entity);
        return result;
    }
    public renderData(data: Project[]) {
        return data.map((e) => ({
            ...e,
            finished: e.works.reduce((count, item) => {
                if (item.status === WorkStatus.approved || item.status === WorkStatus.done) {
                    return count + item.count;
                }
                return count;
            }, 0)
        }))
    }

    /**
     * 每小时更新项目排行榜
     */
    @Cron("0 0 * * * *")
    async autoLoadProjectRank() {
        const list = await this.project.find({
            where: {
                status: ProjectStatus.running
            },
            relations: ["works", "works.user"]
        })
        for (const project of list) {
            await this.add(project);
        }
    }

    public async add({ works = [], ...project }: Project, save = true) {
        const group = works.reduce((data, item) => {
            if (!data[item.user.id]) data[item.user.id] = {
                count: 0,
                ...item.user
            };
            if (item.status === WorkStatus.approved) data[item.user.id].count += item.count
            return data;
        }, {}) as { [k in string]: UserSys & { count: number } };
        const list = Object.values(group);
        const data = list.sort((a, b) => b.count - a.count);
        if (save) await this.cacheService.set(
            data,
            this.cacheService.getProjectRankKey(project.id),
        )
        return data;
    }

    public async get(project: Project) {
        return await this.cacheService.has(async () => {
            return await this.add(project, false);
        }, this.cacheService.getProjectRankKey(project.id));
    }
}